package cn.wgx.common.security.config;

import cn.wgx.common.config.web.WebConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 此处配置oauth2登录成功与失败返回的消息格式
 */
@Configuration
public class Oauth2WebMvcConfigurer implements WebMvcConfigurer {

    //增加oauth2返回消息处理器
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(0, new OAuth2ExceptionMessageConverter());
        converters.add(1, new OAuth2AccessTokenMessageConverter());
    }

    /**
     * oauth2 登录失败返回消息格式
     */
    public class OAuth2ExceptionMessageConverter extends AbstractHttpMessageConverter<OAuth2Exception> {

        private final FastJsonHttpMessageConverter delegateMessageConverter;

        public OAuth2ExceptionMessageConverter() {
            super(MediaType.APPLICATION_JSON);
            this.delegateMessageConverter = WebConfig.fastJsonHttpMessageConverter();
        }

        @Override
        protected boolean supports(Class<?> clazz) {
            return OAuth2Exception.class.isAssignableFrom(clazz);
        }

        @Override
        protected OAuth2Exception readInternal(Class<? extends OAuth2Exception> clazz, HttpInputMessage inputMessage)
                throws HttpMessageNotReadableException {
            throw new UnsupportedOperationException(
                    "This converter is only used for converting from externally aqcuired form data");
        }

        @Override
        protected void writeInternal(OAuth2Exception oauth2Exception, HttpOutputMessage outputMessage) throws IOException,
                HttpMessageNotWritableException {
            Map<String, Object> data = new HashMap<>(8);
            //此处设置登录失败返回消息内容
            String s = oauth2Exception.getSummary()
                    .replaceAll("\\\\", "")
                    .replaceAll("\"", "");
            String s1[] = s.split(",");
            for (String a : s1) {
                String[] split = a.split("=");
                data.put(split[0].trim(), split[1].trim().replaceAll("\"", ""));
            }
            data.put("success", false);
            delegateMessageConverter.write(data, MediaType.APPLICATION_JSON, outputMessage);
        }
    }

    /**
     * oauth2 登录成功返回消息格式
     */
    public class OAuth2AccessTokenMessageConverter extends AbstractHttpMessageConverter<OAuth2AccessToken> {

        private final FastJsonHttpMessageConverter delegateMessageConverter;

        public OAuth2AccessTokenMessageConverter() {
            super(MediaType.APPLICATION_JSON);
            this.delegateMessageConverter = WebConfig.fastJsonHttpMessageConverter();
        }

        @Override
        protected boolean supports(Class<?> clazz) {
            return OAuth2AccessToken.class.isAssignableFrom(clazz);
        }

        @Override
        protected OAuth2AccessToken readInternal(Class<? extends OAuth2AccessToken> clazz, HttpInputMessage inputMessage)
                throws IOException, HttpMessageNotReadableException {
            throw new UnsupportedOperationException(
                    "This converter is only used for converting from externally aqcuired form data");
        }

        @Override
        protected void writeInternal(OAuth2AccessToken accessToken, HttpOutputMessage outputMessage) throws IOException,
                HttpMessageNotWritableException {
            Map<String, Object> data = new HashMap<>(8);
            //此处设置登录成功返回消息内容
            data.put(OAuth2AccessToken.ACCESS_TOKEN, accessToken.getValue());
            data.put(OAuth2AccessToken.TOKEN_TYPE, accessToken.getTokenType());
            data.put(OAuth2AccessToken.EXPIRES_IN, accessToken.getExpiresIn());
            data.put(OAuth2AccessToken.SCOPE, String.join(" ", accessToken.getScope()));
            data.put("success", true);

            OAuth2RefreshToken refreshToken = accessToken.getRefreshToken();
            if (Objects.nonNull(refreshToken)) {
                data.put(OAuth2AccessToken.REFRESH_TOKEN, refreshToken.getValue());
            }
            delegateMessageConverter.write(data, MediaType.APPLICATION_JSON, outputMessage);
        }
    }




    static {
//此方法过时
//        SerializeConfig globalInstance = SerializeConfig.getGlobalInstance();
////        //自定义序列化工具
////        //自定义oauth2登录错误返回信息格式,fastjson利用序列化实现,如果是jackson则不需要特殊配置
////        //处理InvalidGrantException消息内容,保留关键信息
////        globalInstance.put(InvalidGrantException.class,
////                new ObjectSerializer() {
////                    @Override
////                    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
////                        OAuth2Exception responseEntity = (OAuth2Exception) object;
////                        if (responseEntity != null) {
////                            String s = responseEntity.getSummary()
////                                    .replaceAll("\\\\", "")
////                                    .replaceAll("\"", "");
////                            if (s != null) {
////                                JSONObject j = new JSONObject();
////                                String s1[] = s.split(",");
////                                for (String a : s1) {
////                                    String[] split = a.split("=");
////                                    j.put(split[0].trim(), split[1].trim().replaceAll("\"", ""));
////                                }
////                                System.out.println(j.toJSONString());
//////                                serializer.write(j,MediaType.APPLICATION_JSON);
////                                serializer.writeAs(j, JSONObject.class);
////                            }
////                        }
////                    }
////                });
    }

}
